﻿using System;
using SoftwareConsulting.BI11.NumericalMethods.DhbFunctionEvaluation;

namespace SoftwareConsulting.BI11.NumericalMethods.Iterations
{
    /// <summary>
    /// Класс непрерывной дроби
    /// </summary>
    public abstract class ContinuedFraction : IterativeProcess
    {	    
        private double _result;//наилучшее приближение        
        private double _x;//аргумент дроби	    
        private double _numerator;//числитель дроби	    
        private double _denominator;//знаменатель дроби
        private double[] _factors = new double[2];

        /// <summary>
        /// Возвращает/устанавливает аргумент дроби
        /// </summary>
        protected double X
        {
            get
            {
                return _x;
            }
            set
            {
                _x = value;
            }
        }        

        /// <summary>
        /// Возвращает/устанавливает дроби
        /// </summary>
        protected double[] Factors
        {
            get
            {
                return _factors;
            }
            set
            {
                _factors = value;
            }
        }

        /// <summary>
        /// Вычисляет указанную дробь
        /// </summary>
        /// <param name="factorsIndex"></param>
        protected abstract void ComputeFactorsAt(int factorsIndex);

        /// <summary>
        /// Выполняет итерацию
        /// </summary>
        /// <returns></returns>
        public override double DoIteration()
        {
            ComputeFactorsAt(IterationsCount);
            _denominator = 1 / GetCorrectedValue(_factors[0] * _denominator + _factors[1]);
            _numerator = GetCorrectedValue(_factors[0] / _numerator + _factors[1]);
            double delta = _numerator * _denominator;
            _result *= delta;
            return Math.Abs(delta - 1);
        }

        /// <summary>
        /// Возвращает наилучшее приближение дроби
        /// </summary>
        public double Result
        {
            get 
            { 
                return _result; 
            }
        }

        /// <summary>
        /// Создает начальную дробь
        /// </summary>
        public override void CreateRandomPopulation()
        {            
            _numerator = GetCorrectedValue(InitializeValue());
            _denominator = 0;
            _result = _numerator;
        }

        /// <summary>
        /// Инициализирует значение
        /// </summary>
        /// <returns></returns>
        protected abstract double InitializeValue();
        
        /// <summary>
        /// Возвращает значение, скорректированное относительно минимально допустимых значение
        /// </summary>
        /// <param name="r"></param>
        /// <returns></returns>
        private double GetCorrectedValue(double r)
        {
            return Math.Abs(r) < MathExtended.SmallNumber ? MathExtended.SmallNumber : r;
        }

        /// <summary>
        /// Возвращает/устанавливает аргумент дроби
        /// </summary>
        public double Argument
        {
            get
            {
                return _x;
            }
            set 
            {
                _x = value; 
            }
        }
    }
}
